#!/bin/env python2.5.1
import Dingo.API as api #Imports the SenSor API
import Dingo.models.OneHopP2P as P2P 
import Dingo.models.FloodRouter as FloodRouter
import random, Image
import Hi,debugWin,Interpol,Isopleth
import time
#import sys, os

#Static variables
NUMSENSOR = 10      #The number of sensor nodes
scatterNodes = 256  #Topography area
sendDelay = 2       #Approx. delay between different nodes transmission
tdist = 170         #Radio transmission range
c_LIFE = 1000       #Time for each cluser round
STIME = 20          #Time a CH waits before it creates and sends a TDMA schedule

#pathname = os.path.dirname(sys.argv[0])
#fullpath = pathname,'/landsc.png'
#print fullpath

'''
createDebug(parent,id,title) Creates the debug window should be called within the main method 
* Parent: The Windows Parent 
* Id: The wxWindow Id of the display, Generally set this to -1 for automatic assignment 
* Title: The title at the top of the debug window
'''

display = debugWin.createDebug(None,-1,"Mapping Interface",False)

class TheSimulation(api.Simulation):    #Main class Required to run as a sensor module
    def __init__(self, graph):          #Initialise the program
        ether = api.Ether(self)         #Setup the transmission medium
        ether.RF_radius = tdist         #Setuup the radio radius
        im = Image.open("/home/hammoudeh/dingo/test/MuMHR/landsc.png")    #Get map data
        #im = Image.open("pathname/landsc.png")    #Get map data
        BSsensor = Ssensor(graph, ether, -1, NUMSENSOR)     #Create sink node
        sensors = [aSensor(graph,ether,i,im) for i in xrange(NUMSENSOR)]        #Create sensor nodes
        sensors.append(BSsensor)        #Add the sink node the network
        api.Simulation.__init__(self, sensors, graph)       #Initialise the simulation
        graph.addBackground("/MuMHR/landsc.png")
        #graph.addBackground("im")
    def run(self):  #Must have to Run the simulation
        super(TheSimulation, self).run()    #Run the Simulation


class Ssensor(api.Sensor): #Define the behaviour of the sink object
    def __init__(self,graph,ether,i, NUMSENSOR): 
        #Define the sink location
        x = scatterNodes/2
        y = scatterNodes/2

        self.state = "Sink" #Initial sink state
        self.points = {}    #Store sink data
        self.Routing = Hi.sinkRouting(self, NUMSENSOR)  #Define routing protocol

        #Create A List of Tasks to be Preformed
        taskList = [initialize(self), receiveTask(self)]
        #Initilise the Scheduler for this sensor
        #(<self>,<graph>,<Sensor><(X,Y)coords>,<Sensor Color>,<Scheduler Tasks>,<Ether>
        api.Sensor.__init__(self,"Sink[%d]" %i, (x,y),api.SensorColor.Red, api.Scheduler(taskList,-1),ether,P2P.OneHopP2P(),5)

        #show sensor on graph
        #self.node.SetPlotAxes((0,20), 10)
        #self.node.SetPlotAxisLabels('Sink[%d]'%i,'Amount', 'Time')

class aSensor(api.Sensor): #Define the behaviour of sensor nodes
    def __init__(self,graph,ether,i,Im): 
        #Define the sensor node location
        x = random.randrange(0,scatterNodes)
        y = random.randrange(0,scatterNodes)

        z = Im.getpixel((x,y))[0]   #Get sensor reading

        #---------Start Editing---------
        self.number = i         #Set node ID
        self.Routing = Hi.sensorRouting(self)        #Define routing protocol
        self.state = "Waiting"  #Set initial state
        self.isCH = False       #Flag to indicate whether node is CH or not
        self.lastNode = '-'     #Next node in the path to the CH
        self.myCH = '-'         #Store nodes current CH
        self.backupCH = '-'     #Store node to be backup CH node
        self.backupV = 0        #Initial wish value
        self.timestamp = Hi.timeStamp()     #Used to measure cluster round life
        self.AggTimeStamp = Hi.timeStamp()  #data aggregation timer
        self.scheduleTime = Hi.timeStamp()  #Used to time TDMA creation
        self.tdma = True        #False after TDMA is created
        self.seenADV_SCH = []   #Remember all seen ADV_SCH messages
        self.checktdma = False  #If true then check if time to create TDMA
        self.path = []          #Store the path to backup CH node
        self.s_Path = '-'       #The next node in the path to sink
        self.q_Path = '-'       #The next node in the path to querying node
        self.AcceptADV_CH = True  #If false, then ignore received advertisment messages
        self.data = z           #Data packet payload
        self.members = []       #When a node is CH,it stores nodes that belong to this cluster
        self.points = {}        #Node buffer
        self.AGdata = {}        #Used for data aggregation
        self.cQ = []            #Store the seen qerying messages
        self.lastQ = '-'        #Store the Id of querying node
        self.infoFlag = False   #Flag; if true then node generate query
        self.ImFlage = False    

        self.xc = x
        self.yc = y
        #---------End Editing---------

        #Create A List of Tasks to be Preformed
        taskList = [receiveTask(self), checkTask(self),queryTask(self)]
        #Initilise the Scheduler for this sensor
        #(<self>,<graph>,<Sensor><(X,Y)coords>,<Sensor Color>,<Scheduler Tasks>,<Ether>
        api.Sensor.__init__(self,"Sensor[%d]" %i, (x,y),api.SensorColor.White, api.Scheduler(taskList,-1),ether,P2P.OneHopP2P(),5)

        #show sensor on graph
        #self.node.SetPlotAxes((0,20), 10)
        #self.node.SetPlotAxisLabels('Sensor[%d]'%i,'Amount', 'Time')

        #Debug Window
        display.addSensor("Sensor[%d]" %i) #Add this node to the display

        #Add the Buttons
        display.addButton(i,"Generate Map",self.qry)    #Query nodes
        display.addButton(i,"Show Buffer",self.showBuffer)   #Display cached node data
        display.addButton(i,"Display Map",self.calculateMap) #Calculate map from cached data
        display.addButton(i,"Display Isopleth",self.displayIso) #Calculate Isoplths over map

    def qry(self,event):
        self.infoFlag = True

    def showBuffer(self,event):
        display.addOutput(self.number,str(self.points))

    def calculateMap(self,event):
        display.addOutput(self.number,str("Displaing Terrain. Please wait..."))

        self.imsize=(scatterNodes,scatterNodes) #Map size
        self.exponent = 2           #Interpolation exponent
        self.map_im=Image.new("RGB",self.imsize)    #Create new image/map
        l = []

        #Covert dictionary to a list
        for i in self.points.keys():
            l.append(self.points[i])
        self.Points = l     #Pass node data to interpolation module

        Interpol.mappoints_simple(self.Points,self.map_im,self.exponent,75) #Call interpolation
        self.map_im.save("total.png")   #Save interpolation result

        self.map_im.show()          #Display interpolation result

    def displayIso(self,event):
        display.addOutput(self.number,str("Displaing Isopleth. Please wait..."))

        self.a=Image.open("total.png").convert("L")
        self.i,self.o=Isopleth.gather_draw(self.a,165,2)
        self.o.save("Iso.png")

        self.o.show()       #Display isoplth


class receiveTask(api.Task): #Define node behaviour upon receiving a packet
    def __init__(self, sensor):
        # self, priority, repetitions, ref-to-sensor
        api.Task.__init__(self, 0, 0, sensor)

    def task(self):
        while not self.sensor.recv_q.empty():
            themsg = self.sensor.recv_q.get()
            self.sensor.Routing.receiveTask(themsg)


class checkTask(api.Task):
    def __init__(self, sensor):
        api.Task.__init__(self, 0, 0, sensor)

    def task(self):
        if self.sensor.timestamp.diff(Hi.timeStamp()) >= c_LIFE:
            if self.sensor.isCH:
                api.Sleep(2) #Very important
                self.sensor.Routing.checkExpires()
            else:
                self.sensor.Routing.checkExpires()

        if self.sensor.AcceptADV_CH == True and self.sensor.myCH != '-' and not self.sensor.isCH:
            self.sensor.Routing.CheckTime()

        if self.sensor.isCH and self.sensor.checktdma and self.sensor.scheduleTime.diff(Hi.timeStamp()) >= STIME and self.sensor.tdma:
            self.sensor.Routing.createTDMA()

        if len(self.sensor.AGdata) > 0 and self.sensor.AggTimeStamp.diff(Hi.timeStamp()) >= 10:
            self.sensor.Routing.emptyAGdata()

class queryTask(api.Task):
    def __init__(self,sensor):
        api.Task.__init__(self,0,0,sensor)

    def task(self):
        if self.sensor.infoFlag == True:
            self.sensor.infoFlag = False
            if self.sensor.state == "Actuator" and self.sensor.myCH != '-':
				self.sensor.debug("RADIO: %s    send    Query" % self.sensor.id)
				self.sensor.Routing.sendQuery()

class initialize(api.Task):
    def __init__(self, sensor):
        api.Task.__init__(self, 0, 0, sensor)

    def task(self):
        if self.sensor.state == "Sink":
            self.sensor.Routing.StartUp()